package org.light.limitedverb;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.light.core.Writeable;
import org.light.domain.Domain;
import org.light.domain.Dropdown;
import org.light.domain.Field;
import org.light.domain.Method;
import org.light.domain.Signature;
import org.light.domain.Statement;
import org.light.domain.Type;
import org.light.generator.NamedStatementListGenerator;
import org.light.utils.DomainTokenUtil;
import org.light.utils.InterVarUtil;
import org.light.utils.StringUtil;
import org.light.utils.TableStringUtil;
import org.light.utils.WriteableUtil;

public class CountSearchByFieldsRecords extends NoControllerVerb {

	@Override
	public Method generateDaoImplMethod() throws Exception{	
		Method method = new Method();
		method.setStandardName(StringUtil.lowerFirst(this.getVerbName()));
		method.setReturnType(new Type("Integer"));
		method.addAdditionalImport(this.domain.getPackageToken()+"."+this.domain.getDomainSuffix()+"."+this.domain.getCapFirstDomainNameWithSuffix());
		method.addSignature(new Signature(1,"connection",new Type("Connection","java.sql"),"java.sql"));
		method.addSignature(new Signature(2,this.domain.getLowerFirstDomainName(),this.domain.getType(),this.domain.getPackageToken(),"Param(value=\""+this.domain.getLowerFirstDomainName()+"\")"));
		if (this.domain.containsDateTime()) {
			method.addAdditionalImport(this.domain.getPackageToken()+".utils.DateUtil");
		}
		
		List<Writeable> list = new ArrayList<Writeable>();
		
		list.add(new Statement(100,2,"try {"));
		list.add(new Statement(400L,2,"String query = \" select count(*) countSum from "+ domain.getDbPrefix() + TableStringUtil.domainNametoTableName(domain)+" where 1=1 \";"));
		
		long serial = 500L;
		Set<Field> fields = this.domain.getSearchFields();
		for (Field f:fields){
			if (f.getFieldType().equalsIgnoreCase("string")){
				list.add(new Statement(serial,2,"if ("+this.domain.getLowerFirstDomainName()+"."+f.getGetterCall()+"!=null && !\"\".equals("+this.domain.getLowerFirstDomainName()+"."+f.getGetterCall()+")){"));
				list.add(new Statement(serial+100,3,"query += \" and "+DomainTokenUtil.changeDomainFieldtoTableColum(f.getFieldName())+" like ? \";"));
			} else if (f.getFieldType().equalsIgnoreCase("date") || f.getFieldType().equalsIgnoreCase("datetime")){
				list.add(new Statement(serial,2,"if ("+this.domain.getLowerFirstDomainName()+"."+f.getGetterCall()+"!=null){"));
				list.add(new Statement(serial+100,3,"query += \" and date("+DomainTokenUtil.changeDomainFieldtoTableColum(f.getFieldName())+") = date(?) \";"));
			} else{
				list.add(new Statement(serial,2,"if ("+this.domain.getLowerFirstDomainName()+"."+f.getGetterCall()+"!=null ){"));
				list.add(new Statement(serial+100,3,"query += \" and "+DomainTokenUtil.changeDomainFieldtoTableColum(f.getFieldName())+" = ? \";"));
			}
			list.add(new Statement(serial+200,2,"}"));
			serial += 300L;
		}
		list.add(new Statement(serial,2,"query += \";\";"));
		list.add(new Statement(serial+100,2,"//System.out.println(\"JerryDebug:query:\"+query);"));
		list.add(new Statement(serial+200,2,""));
		list.add(new Statement(serial+300,2,"int serial = 1;"));
		list.add(new Statement(serial+400,2,"PreparedStatement ps = connection.prepareStatement(query);"));
		list.add(new Statement(serial+500,2,""));
		
		serial += 600L;

		for (Field f:fields){
			if (f.getFieldType().equalsIgnoreCase("string")){
				list.add(new Statement(serial,2,"if ("+this.domain.getLowerFirstDomainName()+"."+f.getGetterCall()+"!=null && !\"\".equals("+this.domain.getLowerFirstDomainName()+"."+f.getGetterCall()+")){"));
				list.add(new Statement(serial+100,3,"ps.setString(serial++,\"%\"+"+this.domain.getLowerFirstDomainName()+"."+f.getGetterCall()+"+\"%\");"));
			} else if (f.getFieldType().equalsIgnoreCase("date") || f.getFieldType().equalsIgnoreCase("datetime")){
				list.add(new Statement(serial,2,"if ("+this.domain.getLowerFirstDomainName()+"."+f.getGetterCall()+" != null){"));
				list.add(new Statement(serial+100,3,"ps.setDate(serial++, DateUtil.utilDateToSqlDate("+this.domain.getLowerFirstDomainName()+"."+f.getGetterCall()+"));"));
			} else {
				list.add(new Statement(serial,2,"if ("+this.domain.getLowerFirstDomainName()+"."+f.getGetterCall()+" != null){"));
				list.add(new Statement(serial+100,3,"ps.set"+StringUtil.capFirst(f.getPrimaryType().getTypeName())+"(serial++,"+this.domain.getLowerFirstDomainName()+"."+f.getGetterCall()+");"));
			}
			list.add(new Statement(serial+200,2,"}"));
			serial += 300L;
		}
		list.add(new Statement(serial+200,2,""));
		list.add(new Statement(serial+300,2,"ResultSet result = ps.executeQuery();"));
		list.add(new Statement(serial+400,2,"Integer countSum = 0;"));
		list.add(new Statement(serial+500,2,"while(result.next()) {"));
		list.add(new Statement(serial+600,3,"countSum = result.getInt(\"countSum\");"));
		list.add(new Statement(serial+700,2,"}"));
		list.add(new Statement(serial+800,2,"return countSum;"));
		list.add(new Statement(serial+900,2,"} catch (Exception e){"));
		list.add(new Statement(serial+1000,3,"e.printStackTrace();"));
		list.add(new Statement(serial+1100,3,"return 0;"));
		list.add(new Statement(serial+1200,2,"}"));
				
		method.setMethodStatementList(WriteableUtil.merge(list));
		return method;
	}

	@Override
	public String generateDaoImplMethodString()  throws Exception{
		Method m = this.generateDaoImplMethod();
		String s = m.generateMethodString();
		return s;
	}

	@Override
	public String generateDaoImplMethodStringWithSerial()  throws Exception{
		Method m = this.generateDaoImplMethod();
		m.setContent(m.generateMethodContentStringWithSerial());
		m.setMethodStatementList(null);
		return m.generateMethodString();
	}

	@Override
	public Method generateDaoMethodDefinition()  throws Exception{
		Method method = new Method();
		method.setStandardName("countSearch"+this.domain.getCapFirstPlural()+"ByFieldsRecords");
		method.setReturnType(new Type("Integer"));
		method.addAdditionalImport(this.domain.getPackageToken()+"."+this.domain.getDomainSuffix()+"."+this.domain.getCapFirstDomainNameWithSuffix());
		method.addSignature(new Signature(1,"connection",new Type("Connection","java.sql"),"java.sql"));
		method.addSignature(new Signature(2,this.domain.getLowerFirstDomainName(),this.domain.getType(),this.domain.getPackageToken()));		
		method.setThrowException(true);
		return method;
	}

	@Override
	public String generateDaoMethodDefinitionString()  throws Exception{
		return generateDaoMethodDefinition().generateMethodDefinition();
	}

	@Override
	public Method generateServiceMethodDefinition()  throws Exception{
		Method method = new Method();
		method.setStandardName("countSearch"+this.domain.getCapFirstPlural()+"ByFieldsRecords");
		method.setReturnType(new Type("Integer"));
		method.addAdditionalImport(this.domain.getPackageToken()+"."+this.domain.getDomainSuffix()+"."+this.domain.getCapFirstDomainNameWithSuffix());
		method.addSignature(new Signature(1,this.domain.getLowerFirstDomainName(),this.domain.getType()));
		method.setThrowException(true);
		
		return method;
	}

	@Override
	public String generateServiceMethodDefinitionString()  throws Exception{
		return generateServiceMethodDefinition().generateMethodDefinition();
	}

	@Override
	public Method generateServiceImplMethod()  throws Exception{
		Method method = new Method();
		method.setStandardName("countSearch"+this.domain.getCapFirstPlural()+"ByFieldsRecords");
		method.setReturnType(new Type("Integer"));
		method.addAdditionalImport(this.domain.getPackageToken()+"."+this.domain.getDomainSuffix()+"."+this.domain.getCapFirstDomainNameWithSuffix());
		method.addAdditionalImport(this.domain.getPackageToken()+"."+this.domain.getDaoSuffix()+"."+this.domain.getStandardName()+"Dao");
		method.addAdditionalImport(this.domain.getPackageToken()+"."+this.domain.getServiceSuffix()+"."+this.domain.getStandardName()+"Service");
		method.addSignature(new Signature(1,this.domain.getLowerFirstDomainName(),this.domain.getType()));
		method.setThrowException(true);
		method.addMetaData("Override");
		
		Method daomethod = this.generateDaoMethodDefinition();		
		List<Writeable> list = new ArrayList<Writeable>();
		list.add(NamedStatementListGenerator.generateServiceImplReturnInt(1000L, 2, InterVarUtil.DB.connection, InterVarUtil.DB.dbconf, this.domain, InterVarUtil.DB.dao, daomethod));
		method.setMethodStatementList(WriteableUtil.merge(list));

		return method;
	}

	@Override
	public String generateServiceImplMethodString()  throws Exception{
		return generateServiceImplMethod().generateMethodString();
	}

	@Override
	public String generateServiceImplMethodStringWithSerial() throws Exception{
		Method m = this.generateServiceImplMethod();
		m.setContent(m.generateMethodContentStringWithSerial());
		m.setMethodStatementList(null);
		return m.generateMethodString();
	}
	
	public CountSearchByFieldsRecords(Domain domain){
		super();
		this.domain = domain;
		this.verbName = "countSearch"+this.domain.getCapFirstPlural()+"ByFieldsRecords";
	}
	
	public CountSearchByFieldsRecords(){
		super();
	}

	@Override
	public Method generateDummyDaoImplMethod() throws Exception {
		if (this.denied)
			return null;
		else {
			Method method = new Method();
			method.setStandardName(StringUtil.lowerFirst(this.getVerbName()));
			method.setReturnType(new Type("Integer"));
			method.addAdditionalImport(this.domain.getPackageToken() + ".utils.StringUtil");
			method.addSignature(new Signature(1, this.domain.getLowerFirstDomainName(), this.domain.getType(),
					this.domain.getPackageToken()));
			method.addAdditionalImport(this.domain.getPackageToken() + "." + this.domain.getDomainSuffix() + "."
					+ this.domain.getCapFirstDomainNameWithSuffix());
			method.setThrowException(true);
			
			List<Writeable> sList = new ArrayList<Writeable>();
			long serial = 1000L;			
			sList.add(new Statement(serial+1000L,2,"List<"+this.domain.getCapFirstDomainNameWithSuffix()+"> result = new ArrayList<>();"));
			sList.add(new Statement(serial+2000L,2,"for ("+this.domain.getCapFirstDomainNameWithSuffix()+" raw"+this.domain.getLowerFirstDomainName()+" : db){"));
			sList.add(new Statement(serial+3000L,3,"boolean matches = true;"));
			serial += 4000L;
			for (Field f: this.domain.getSearchFields()) {
				if (! deniedFields.contains(f)) {
					if (f instanceof Dropdown) {
						sList.add(new Statement(serial,3,"if ("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() != null) {"));
						sList.add(new Statement(serial+1000L,4,"if (!raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"().equals("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"())) matches = false;"));
						sList.add(new Statement(serial+2000L,3,"}"));
					} else if ("String".equalsIgnoreCase(f.getFieldType())){					
						sList.add(new Statement(serial,3,"if (!StringUtil.isBlank("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"())) {"));
						sList.add(new Statement(serial+1000L,4,"if (!raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"().contains("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"())) matches = false;"));
						sList.add(new Statement(serial+2000L,3,"}"));
					} else if ("int".equals(f.getFieldType())||"Integer".equals(f.getFieldType())||"long".equalsIgnoreCase(f.getFieldType())){
						sList.add(new Statement(serial,3,"if ("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() != null) {"));
						sList.add(new Statement(serial+1000L,4,"if (!raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"().equals("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"())) matches = false;"));
						sList.add(new Statement(serial+2000L,3,"}"));
					} else if ("float".equalsIgnoreCase(f.getFieldType())){
						sList.add(new Statement(serial,3,"if ("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() != null) {"));
						sList.add(new Statement(serial+1000L,4,"if (Math.abs(raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() - "+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"()) > 0.0001) matches = false;"));
						sList.add(new Statement(serial+2000L,3,"}"));
					} else if ("float".equalsIgnoreCase(f.getFieldType())||"double".equalsIgnoreCase(f.getFieldType())){
						sList.add(new Statement(serial,3,"if ("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() != null) {"));
						sList.add(new Statement(serial+1000L,4,"if (Math.abs(raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() - "+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"()) > 0.0001) matches = false;"));
						sList.add(new Statement(serial+2000L,3,"}"));
					} else if ("boolean".equalsIgnoreCase(f.getFieldType())){
						sList.add(new Statement(serial,3,"if ("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() != null) {"));
						sList.add(new Statement(serial+1000L,4,"if (!raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"().equals("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"())) matches = false;"));
						sList.add(new Statement(serial+2000L,3,"}"));
					} else if ("datetime".equalsIgnoreCase(f.getFieldType())){
						sList.add(new Statement(serial,3,"if ("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() != null) {"));
						sList.add(new Statement(serial+500L,4,"SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd\");"));
						sList.add(new Statement(serial+1000L,4,"if (raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() == null || (raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() != null && sdf.format(raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"()).compareTo(sdf.format("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"())) != 0)) matches = false;"));
						sList.add(new Statement(serial+2000L,3,"}"));
					} else if ("date".equalsIgnoreCase(f.getFieldType())){
						sList.add(new Statement(serial,3,"if ("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() != null) {"));
						sList.add(new Statement(serial+1000L,4,"if (raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() == null || (raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() != null && raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"().compareTo("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"()) != 0)) matches = false;"));
						sList.add(new Statement(serial+2000L,3,"}"));
					}					
					serial += 3000L;
				}
			}
			sList.add(new Statement(serial,3,"if (matches) result.add(raw"+this.domain.getLowerFirstDomainName()+");"));
			sList.add(new Statement(serial+1000L,2,"}"));
			sList.add(new Statement(serial+2000L,2,"return result.size();"));
			method.setMethodStatementList(WriteableUtil.merge(sList));
			return method;
		}
	}

	@Override
	public Method generateDummyServiceImplMethod() throws Exception {
		if (this.denied)
			return null;
		else {
			Method method = new Method();
			method.setStandardName(StringUtil.lowerFirst(this.getVerbName()));
			method.setReturnType(new Type("Integer"));
			method.addSignature(new Signature(1, this.domain.getLowerFirstDomainName(), this.domain.getType()));
			method.setThrowException(true);
			method.addAdditionalImport("java.util.List");
			method.addAdditionalImport(this.domain.getPackageToken() + "." + this.domain.getDomainSuffix() + "."
					+ this.domain.getCapFirstDomainNameWithSuffix());
			method.addAdditionalImport(this.domain.getPackageToken() + "." + this.domain.getDaoSuffix() + "."
					+ this.domain.getStandardName() + "Dao");
			method.addAdditionalImport(this.domain.getPackageToken() + "." + this.domain.getServiceSuffix() + "."
					+ this.domain.getStandardName() + "Service");
			method.addMetaData("Override");

			List<Writeable> list = new ArrayList<Writeable>();
			Method daomethod = this.generateDummyDaoMethodDefinition();
			list.add(new Statement(200L,2, "return " + daomethod.generateStandardServiceImplCallString(InterVarUtil.DB.dao.getVarName())+";"));
			method.setMethodStatementList(WriteableUtil.merge(list));
			return method;
		}
	}

	@Override
	public Method generateDummyDaoMethodDefinition() throws Exception {
		if (this.denied)
			return null;
		else {
			Method method = new Method();
			method.setStandardName(StringUtil.lowerFirst(this.getVerbName()));
			method.setReturnType(new Type("Integer"));
			method.addSignature(new Signature(1, this.domain.getLowerFirstDomainName(), this.domain.getType()));
			method.setThrowException(true);
			return method;
		}
	}
}
